package com.dbflow5.config;

import com.dbflow5.adapter.ModelAdapter;
import com.dbflow5.adapter.queriable.ListModelLoader;
import com.dbflow5.adapter.queriable.SingleModelLoader;
import com.dbflow5.adapter.saveable.ModelSaver;

/**
 * Description: Represents certain table configuration options. This allows you to easily specify
 * certain configuration options for a table.
 */
public class TableConfig<T>{

    public Class<T> tableClass;
    public ModelSaver<T> modelSaver;
    public SingleModelLoader<T> singleModelLoader;
    public ListModelLoader<T> listModelLoader;

    public TableConfig(Class<T> tableClass, ModelSaver<T> modelSaver, SingleModelLoader<T> singleModelLoader, ListModelLoader<T> listModelLoader){
        this.tableClass = tableClass;
        this.modelSaver = modelSaver;
        this.singleModelLoader = singleModelLoader;
        this.listModelLoader = listModelLoader;
    }

    public TableConfig(Builder<T> builder){
        tableClass = builder.tableClass;
        modelSaver = builder.modelAdapterModelSaver;
        singleModelLoader = builder.singleModelLoader;
        listModelLoader = builder.listModelLoader;
    }

    /**
     * Table builder for java consumers. use [TableConfig] directly if calling from Kotlin.
     */
    static class Builder<T>{

        private final Class<T> tableClass;

        public ModelSaver<T> modelAdapterModelSaver = null;
        public SingleModelLoader<T> singleModelLoader = null;
        public ListModelLoader<T> listModelLoader = null;

        Builder(Class<T> tableClass){
            this.tableClass = tableClass;
        }

        /**
         * Define how the [ModelAdapter] saves data into the DB from its associated [T]. This
         * will override the default.
         *
         * @param modelSaver modelSaver
         * @return this
         */
        public Builder<T> modelAdapterModelSaver(ModelSaver<T> modelSaver) {
            this.modelAdapterModelSaver = modelSaver;
            return this;
        }

        /**
         * Define how the table loads single models. This will override the default.
         *
         * @param singleModelLoader singleModelLoader
         * @return this
         */
        public Builder<T> singleModelLoader(SingleModelLoader<T> singleModelLoader) {
            this.singleModelLoader = singleModelLoader;
            return this;
        }

        /**
         * Define how the table loads a [List] of items. This will override the default.
         *
         * @param listModelLoader listModelLoader
         * @return this
         */
        public Builder<T> listModelLoader(ListModelLoader<T> listModelLoader) {
            this.listModelLoader = listModelLoader;
            return this;
        }

        /**
         * build
         *
         * @return A new [TableConfig]. Subsequent calls to this method produce a new instance of [TableConfig].
         */
        public TableConfig<?> build(){
            return new TableConfig<>(this);
        }
    }

    public static <T> Builder<T> builder(Class<T> tableClass) {
        return new Builder<T>(tableClass);
    }
}
